home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / htmlsample / renderingwindow.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  29.5 KB  |  930 lines

  1. /*
  2.     file RenderingWindow.c
  3.     
  4.     Description:
  5.     This file contains the routines used to manage the windows displayed
  6.     by the HTMLSample application.
  7.     
  8.     HTMLSample is an application illustrating how to use the new
  9.     HTMLRenderingLib services found in Mac OS 9. HTMLRenderingLib
  10.     is Apple's light-weight HTML rendering engine capable of
  11.     displaying HTML files.
  12.  
  13.     by John Montbriand, 1999.
  14.  
  15.     Copyright: © 1999 by Apple Computer, Inc.
  16.     all rights reserved.
  17.     
  18.     Disclaimer:
  19.     You may incorporate this sample code into your applications without
  20.     restriction, though the sample code has been provided "AS IS" and the
  21.     responsibility for its operation is 100% yours.  However, what you are
  22.     not permitted to do is to redistribute the source as "DSC Sample Code"
  23.     after having made changes. If you're going to re-distribute the source,
  24.     we require that you make it clear in the source that the code was
  25.     descended from Apple Sample Code, but that you've made changes.
  26.     
  27.     Change History (most recent first):
  28.     10/16/99 created by John Montbriand
  29. */
  30.  
  31. #include "RenderingWindow.h"
  32.  
  33. #include <HTMLRendering.h>
  34. #include <Resources.h>
  35. #include <StdDef.h>
  36. #include <string.h>
  37. #include <Sound.h>
  38.  
  39. #include "History.h"
  40. #include "CIconButtons.h"
  41. #include "SampleUtils.h"
  42. #include "HTMLSample.h"
  43.  
  44.  
  45.     /* resource id numbers for PICT resources used
  46.     for drawing the fill area to the right of the buttons */
  47. enum {
  48.     kLeftBarPicture = 128,
  49.     kCenterBarPicture = 129,
  50.     kRightBarPicture = 130
  51. };
  52.  
  53.     /* ASCII codes for the arrow keys on the keyboard */
  54. enum {
  55.     kLeftArrowKey = 28,
  56.     kUpArrowKey = 30,
  57.     kDownArrowKey = 29
  58. };
  59.  
  60.     /* color icon button resources for the default
  61.     navigation buttons. */
  62. enum {
  63.     kBackDefaultButton = 128,
  64.     kHomeDefaultButton = 129,
  65.     kForwardDefaultButton = 130
  66. };
  67.  
  68.     /* constants used for adding custom buttons. */
  69. enum {
  70.     kExtraButtonsMax = 4,
  71.     kExtraButtonsListID = 128
  72. };
  73.  
  74.     /* the resource id for the main window's
  75.     WIND resource. */
  76. enum {
  77.     kRenderingWindowID = 128
  78. };
  79.  
  80.  
  81.  
  82.  
  83. /* RWindowHandle's refer to a data structure created
  84.     for each rendering window to store various state
  85.     variables used for maintaining the window on the
  86.     screen.  Most importantly, for this example, this
  87.     is where a reference to the HTML rendering object
  88.     is stored.  A handle to this structure is stored in
  89.     the rendering window's refcon field. */
  90.     
  91. typedef struct RWindowStruct RWindowVars;
  92. typedef RWindowVars **RWindowHandle;
  93.  
  94. struct RWindowStruct {
  95.     RWindowHandle prev, next; /* list of open rendering windows */
  96.     WindowPtr rwindow;    /* a pointer to the window */
  97.     HRReference renderer;    /* a reference to the rendering object */
  98.     HistoryDataHandle history;    /* history of visited links for this window */
  99.     Boolean isActive;    /* true when this window is the frontmost window. */
  100.     CIconButtonHandle bback, bhome, bforward;    /* the default buttons */
  101.     short nExtraButtons; /* the number of extra buttons */
  102.     CIconButtonHandle extraButtons[1]; /* handles to the extra buttons */
  103. };
  104.  
  105.  
  106.     /* these picture handles are used for drawing the fill area
  107.     to the right of the buttons in the top of the window.  The
  108.     resources these variables reference are read in when
  109.     InitRenderingWindows is called. */
  110. PicHandle gFBLeft = NULL, gFBCenter = NULL, gFBRight = NULL;
  111.  
  112.  
  113.     /* a list of open rendering windows. */
  114. RWindowHandle gRWFirst = NULL, gRWLast = NULL;
  115.  
  116.  
  117.     /* the global history is used to store 'all' visited links for
  118.     every window.  */
  119. HistoryDataHandle gGlobalHistory = NULL;
  120.  
  121.  
  122.     /* gRenderingWindowsOpen is set to true when InitRenderingWindows
  123.         is successful. */
  124. Boolean gRenderingWindowsOpen = false;
  125.  
  126.  
  127. /* InitRenderingWindows is called to initialize the environment used by 
  128.     routines defined in this file.  It should be called before any of the 
  129.     other routines defined in this file are called. */
  130. OSStatus InitRenderingWindows(void) {
  131.         /* get the pictures for drawing the fill
  132.         area to the right of the buttons from the
  133.         resource file */
  134.     gFBLeft = GetPicture(kLeftBarPicture);
  135.     if (gFBLeft == NULL) return resNotFound;
  136.     gFBCenter = GetPicture(kCenterBarPicture);
  137.     if (gFBCenter == NULL) return resNotFound;
  138.     gFBRight = GetPicture(kRightBarPicture);
  139.     if (gFBRight == NULL) return resNotFound;
  140.         /* initialize the list of opened windows */
  141.     gRWFirst = gRWLast = NULL;
  142.         /* allocate the global history */
  143.     gGlobalHistory = NewHistory();
  144.     if (gGlobalHistory == NULL) return memFullErr;
  145.         /* set the open flag */
  146.     gRenderingWindowsOpen = true;
  147.         /* done */
  148.     return noErr;
  149. }
  150.  
  151.  
  152. /* CloseRenderingWindows closes any open rendering windows and
  153.     deallocates any structures allocated when InitRenderingWindows
  154.     was called. */
  155. OSStatus CloseRenderingWindows(void) {
  156.     if (gRenderingWindowsOpen) {
  157.             /* close any open rendering windows */
  158.         while (gRWFirst != NULL)
  159.             RWCloseWindow((**gRWFirst).rwindow);
  160.             /* release the global history */
  161.         DisposeHistory(gGlobalHistory);
  162.             /* reset the open flag */
  163.         gRenderingWindowsOpen = false;
  164.     }
  165.     return noErr;
  166. }
  167.  
  168.  
  169.  
  170. /* MyHRURLToFSSpecProc is the URL to FSSpec mapping defined for rendering windows.
  171.     it calls the HTMLRenderingLib HRUtilGetFSSpecFromURL routine to map the url
  172.     to a FSSpec and then it checks to see if the file exists and if it's an application.
  173.     If the file does not exist, it re-directs the URL to refer to the error page.  If the
  174.     file exists and it's an application, it launches the application. */
  175. static OSStatus MyHRURLToFSSpecProc(const char *rootURL, const char *linkURL,
  176.             FSSpec *fsspec, URLSourceType urlSourceType, void *refCon) {
  177.     RWindowHandle rwv;
  178.     FSSpec spec;
  179.     OSStatus err;
  180.     FInfo fndrInfo;
  181.         /* set up locals */
  182.     rwv = (RWindowHandle) refCon;
  183.         /* as the rendering library to map the file
  184.         for us. */
  185.     err = HRUtilGetFSSpecFromURL(rootURL, linkURL, &spec);
  186.     if (err != noErr) goto bail;
  187.         /* check to see if the file exists. */
  188.     err = FSpGetFInfo(&spec, &fndrInfo);
  189.     if (err != noErr) goto bail;
  190.         /* if the file is an application, launch it */
  191.     if (fndrInfo.fdType == 'APPL') {
  192.         LaunchParamBlockRec launchpb;
  193.         memset(&launchpb, 0, sizeof(launchpb));
  194.         launchpb.launchBlockID = extendedBlock;
  195.         launchpb.launchEPBLength = extendedBlockLen;
  196.         launchpb.launchFileFlags = launchNoFileFlags;
  197.         launchpb.launchControlFlags = launchContinue;
  198.         launchpb.launchAppSpec = &spec;
  199.         err = LaunchApplication(&launchpb);
  200.             /* we return an error so the HTMLRenderingLib
  201.             does not try to draw the file. */
  202.         return fnfErr;
  203.     }
  204.         /* return the FSSpec */
  205.     *fsspec = spec;
  206.     return noErr;
  207. bail:
  208.         /* if an error occured and we're looking for a
  209.         HTML source file, then we re-direct the URL to the
  210.         error file. */
  211.     if (urlSourceType == kHRLookingForHTMLSource) {
  212.         Handle rootURL, errorLink;
  213.             /* the link we have in our resources is application
  214.             relative, so we need to get the application's URL first. */
  215.         if (GetApplicationFolderURL(&rootURL) == noErr) {
  216.                 /* and then we pull the application relative link
  217.                 from the resource file. */
  218.             errorLink = GetResource(kCStyleStringResourceType, kErrorPageURLString);
  219.             if (errorLink != NULL) {
  220.                 HLock(errorLink);
  221.                 HLock(rootURL);
  222.                     /* after retrieving the URL and the link, we ask the
  223.                     rendering library to map them to a FSSpec. */
  224.                 if (HRUtilGetFSSpecFromURL(*rootURL, *errorLink, &spec) == noErr) {
  225.                         /* then, if the file exists, we return a FSSpec referring
  226.                         to the error file. */
  227.                     if (FSpGetFInfo(&spec, &fndrInfo) == noErr) {
  228.                         *fsspec = spec;
  229.                         err = noErr;
  230.                     }
  231.                 }
  232.                 HUnlock(errorLink);
  233.             }
  234.             DisposeHandle(rootURL);
  235.         }
  236.     }
  237.     return err;
  238. }
  239.  
  240.  
  241. /* RedrawWindowButtons redraws the three default buttons in the top
  242.     of the window.  the way they are drawn depends on what commands
  243.     are available at the time when this routine is called. here we set the
  244.     origin to 0,0, and the clip region  to the window's clip region.  We
  245.     do so because when this routine is called the origin and clip region 
  246.     may have been left in an unknown state by the rendering library.*/
  247. static void RedrawWindowButtons(RWindowHandle rwv) {
  248.     RgnHandle clipsave;
  249.         /* set the current grafport to the window's */
  250.     SetPort((**rwv).rwindow);
  251.         /* set the origin before drawing.  it may be incorrect when we're called. */
  252.     SetOrigin(0, 0); 
  253.         /* save the clipping region going to links with anchors sets it incorrectly */
  254.     clipsave = NewRgn(); 
  255.     GetClip(clipsave);
  256.     ClipRect(&(**rwv).rwindow->portRect);
  257.         /* draw the buttons */
  258.     DrawCIconButton((**rwv).bback, (CanGoBack((**rwv).history) ? kCBup : kCBdisabled));
  259.     DrawCIconButton((**rwv).bhome, (CanGoHome((**rwv).history) ? kCBup : kCBdisabled));
  260.     DrawCIconButton((**rwv).bforward, (CanGoForward((**rwv).history) ? kCBup : kCBdisabled));
  261.         /* restore the clipping region */
  262.     SetClip(clipsave);
  263.     DisposeRgn(clipsave);
  264. }
  265.  
  266.  
  267. /* MyNewURLProc is called by the rendering library whenever a new HTML file
  268.     is brought into the display.  This routine will be called with the HTML file's
  269.     URL. if addToHistory is true, then the file is added to the history of visited
  270.     links.  */
  271. static OSStatus MyNewURLProc( const char *url, const char *targetFrame,
  272.         Boolean addToHistory, void *refCon, HRNewURLUPP userUPP) {
  273.     RWindowHandle rwv;
  274.     Str255 title;
  275.     Point theSize;
  276.         /* set up locals */
  277.     rwv = (RWindowHandle) refCon;
  278.         /* set up the drawing environment */
  279.     SetPort((**rwv).rwindow);
  280.     SetOrigin(0, 0);
  281.         /* set the window's title to the new file */
  282.     if (HRGetTitle( (**rwv).renderer, title) == noErr)
  283.         SetWTitle((**rwv).rwindow, title);
  284.     else title[0] = 0;
  285.         /* set the window's standard state rectangle to
  286.         the 'best' size for displaying this page. If the user
  287.         zooms the window, it will go to this size.  */
  288.     if (HRGetRenderedImageSize((**rwv).renderer, &theSize) == noErr)
  289.         SetWindowStandardStateSize((**rwv).rwindow, theSize.h + 16, theSize.v + 32 + 16);
  290.         /* if add to history is true, then we add the URL to both
  291.         the window's history and to the global history. */
  292.     if (addToHistory) {
  293.             /* add to the window's history */
  294.         AddToHistory((**rwv).history, url, title);
  295.             /* add tot the global history. */
  296.         AddToHistory(gGlobalHistory, url, "\p");
  297.             /* redraw the window's controls.  We do
  298.             this here because their visual state depends
  299.             on the state of the window's history. */
  300.         RedrawWindowButtons(rwv);
  301.     }
  302.         /* done */
  303.     return noErr;
  304. }
  305.  
  306.  
  307. /* MyHRWasURLVisitedProc is called by the HTML rendering library
  308.     when it would like to determine if a link has been visited.  This
  309.     information is used when drawing links. */
  310. static Boolean MyHRWasURLVisitedProc(const char *url, void *refCon) {
  311.         /* here we return true if the link can be found in the
  312.         global history of all visited links, not just the window's history. */
  313.     return InHistory(gGlobalHistory, url);
  314. }
  315.  
  316.  
  317. /* URLContainsAnchor returns true if a URL contains
  318.     an anchor.  i.e. it contains a # character. */
  319. static Boolean URLContainsAnchor(char const *url) {
  320.     char const *cp;
  321.     for (cp = url; *cp != '\0'; cp++)
  322.         if (*cp == '#')
  323.             return true;
  324.     return false;
  325. }
  326.  
  327.  
  328. /* RWGotoURL displays HTML file referred to by the url in the
  329.     rendering window.  if addToHistory is true, then the window
  330.     will be added to the window's history list. */
  331. OSStatus RWGotoURL(WindowPtr rWin, char* url, Boolean addToHistory) {
  332.     RWindowHandle rwv;
  333.     OSStatus err;
  334.     Point origin = {0, 0};
  335.     Rect donedrawingbox;
  336.         /* set up locals */
  337.     rwv = (RWindowHandle) GetWRefCon(rWin);
  338.  
  339.         /* if the URL does not contain an anchor, then scroll
  340.         the HTML view to the origin. */
  341.     if ( ! URLContainsAnchor(url)) {
  342.         err = HRScrollToLocation((**rwv).renderer, &origin);
  343.         if (err != noErr) goto bail;
  344.     }
  345.         /* ask the rendering object to display the HTML page
  346.         referred to by the URL.  note, we pass the addToHistory to
  347.         this routine which in turn passes it to our MyNewURLProc
  348.         routine. */
  349.     err = HRGoToURL((**rwv).renderer, url, addToHistory, false);
  350.     if (err != noErr) goto bail;
  351.     
  352.         /* draw the new page */
  353.     err = HRDraw((**rwv).renderer, NULL);
  354.     if (err != noErr) goto bail;
  355.     
  356.         /* if addToHistory is false, then we would not
  357.         have re-drawn the buttons inside of our MyNewURLProc
  358.         routine so we should draw them here. */
  359.     if ( ! addToHistory)
  360.         RedrawWindowButtons(rwv);
  361.         
  362.         /* we validate the areas that were drawn by this
  363.         routine.  This is to avoid unnecessary redraws when
  364.         the window is first opened.  When the window is opened,
  365.         an update event will be posted for its entire contents.
  366.         These calls prevent the areas we have just drawn from
  367.         being re-drawn when the update event is processed. */
  368.     SetRect(&donedrawingbox, 0, 0, 32*3, 32);
  369.     ValidRect(&donedrawingbox);
  370.     donedrawingbox = rWin->portRect;
  371.     donedrawingbox.top += 33;
  372.     ValidRect(&donedrawingbox);
  373.  
  374.         /* done */
  375.     return noErr;
  376. bail:
  377.     return err;
  378. }
  379.  
  380. void debugf(char const *fmt, ...);
  381.  
  382. /* RWGotoAppRelLink displays HTML file referred to by the application
  383.     relative link in the rendering window.  if addToHistory is true, then
  384.     the window will be added to the window's history list. */
  385. OSStatus RWGotoAppRelLink(WindowPtr rWin, char* linkstr, Boolean addToHistory) {
  386.  
  387.     OSStatus err;
  388.     Handle rootURL, fullURL;
  389.         /* set up our locals */
  390.     rootURL = fullURL = NULL;
  391.         /* get the URL for the application's folder */
  392.     err = GetApplicationFolderURL(&rootURL);
  393.     if (err != noErr) goto bail;
  394.         /* allocate a handle for storing the full URL */
  395.     fullURL = NewHandle(0);
  396.     if (fullURL == NULL) { err = memFullErr; goto bail; }
  397.         /* ask the HTML rendering library to combine
  398.         the url and the link to make a complete URL */
  399.     HLock(rootURL);
  400.     err = HRUtilCreateFullURL(*rootURL, linkstr, fullURL);
  401.     if (err != noErr) goto bail;
  402.     HUnlock(rootURL);
  403.         /* call the RWGotoURL to bring the HTML file into view. */
  404.     MoveHHi(fullURL);
  405.     HLock(fullURL);
  406.     err = RWGotoURL(rWin, *fullURL, addToHistory);
  407.     if (err != noErr) goto bail;
  408.         /* clean up our locals */
  409.     DisposeHandle(rootURL);
  410.     DisposeHandle(fullURL);
  411.         /* done */
  412.     return noErr;
  413. bail:
  414.         /* on error, clean up and return the error. */
  415.     if (rootURL != NULL) DisposeHandle(rootURL);
  416.     if (fullURL != NULL) DisposeHandle(fullURL);
  417.     return err;
  418. }
  419.  
  420.  
  421. /* GoBackCommand is called whenever the user chooses
  422.     'go back' by either picking the menu item, clicking on
  423.     the button, or using the left arrow key on the keyboard. */
  424. static void GoBackCommand(RWindowHandle rwv) {
  425.     char** theURL;
  426.         /* get previous the URL from the window's history. */
  427.     if (GoBack((**rwv).history, (Handle*) &theURL) == noErr) {
  428.         MoveHHi((Handle) theURL);
  429.         HLock((Handle) theURL);
  430.             /* call the RWGotoURL routine to bring the
  431.             HTML file referred to by the URL into view. */
  432.         RWGotoURL((**rwv).rwindow, *theURL, false);
  433.  
  434.         DisposeHandle((Handle) theURL);
  435.     }
  436. }
  437.  
  438. /* GoHomeCommand is called whenever the user chooses
  439.     'go home' by either picking the menu item, clicking on
  440.     the button, or using the left arrow key on the keyboard. 
  441.     The file opened by this command will be the first file
  442.     displayed in the window when it was opened. */
  443. static void GoHomeCommand(RWindowHandle rwv) {
  444.     char** theURL;
  445.         /* get first the URL from the window's history. */
  446.     if (GoHome((**rwv).history, (Handle*) &theURL) == noErr) {
  447.         MoveHHi((Handle) theURL);
  448.         HLock((Handle) theURL);
  449.             /* call the RWGotoURL routine to bring the
  450.             HTML file referred to by the URL into view. */
  451.         RWGotoURL((**rwv).rwindow, *theURL, false);
  452.  
  453.         DisposeHandle((Handle) theURL);
  454.     }
  455. }
  456.  
  457.  
  458. /* GoForwardCommand is called whenever the user chooses
  459.     'go forward' by either picking the menu item, clicking on
  460.     the button, or using the left arrow key on the keyboard. */
  461. static void GoForwardCommand(RWindowHandle rwv) {
  462.     char** theURL;
  463.         /* get next the URL from the window's history. */
  464.     if (GoForward((**rwv).history, (Handle*) &theURL) == noErr) {
  465.         MoveHHi((Handle) theURL);
  466.         HLock((Handle) theURL);
  467.             /* call the RWGotoURL routine to bring the
  468.             HTML file referred to by the URL into view. */
  469.         RWGotoURL((**rwv).rwindow, *theURL, false);
  470.  
  471.         DisposeHandle((Handle) theURL);
  472.     }
  473. }
  474.  
  475.  
  476. /* RWGoToButtonPage is called whenever the user clicks on
  477.     a custom button.  This routine attempts to load the
  478.     application relative URL stored in the button's string
  479.     data. */
  480. static OSStatus RWGoToButtonPage(WindowPtr rWin, CIconButtonHandle theButton) {
  481.     RWindowHandle rwv;
  482.     OSStatus err;
  483.     Handle linkURL;
  484.         /* set up locals */
  485.     linkURL = NULL;
  486.     rwv = (RWindowHandle) GetWRefCon(rWin);    
  487.         /* get the application relative link from the button */
  488.     err = GetCIconButtonStringData(theButton, &linkURL);
  489.     if (err != noErr) goto bail;
  490.         /* call RWGotoAppRelLink to bring the HTML file
  491.         referred to by the link into the display. */
  492.     MoveHHi(linkURL);
  493.     HLock(linkURL);
  494.     err = RWGotoAppRelLink(rWin, *linkURL, true);
  495.     if (err != noErr) goto bail;
  496.         /* clean up */
  497.     DisposeHandle(linkURL);
  498.         /* done */
  499.     return noErr;
  500. bail:
  501.     if (linkURL != NULL) DisposeHandle(linkURL);
  502.     return err;
  503. }
  504.  
  505.  
  506.  
  507. /* DrawFillBar draws the fill area to the right of the
  508.     button controls in the top of the window. */
  509. static OSStatus DrawFillBar(Rect *bounds) {
  510.     Rect r;
  511.         /* Draw the left side */
  512.     r = *bounds;
  513.     r.right = r.left + 8;
  514.     DrawPicture(gFBLeft, &r);
  515.         /* draw the center */
  516.     r = *bounds;
  517.     r.left += 8;
  518.     r.right -= 8;
  519.     DrawPicture(gFBCenter, &r);
  520.         /* draw the right side */
  521.     r = *bounds;
  522.     r.left = r.right - 8;
  523.     DrawPicture(gFBRight, &r);
  524.         /* done */
  525.     return noErr;
  526. }
  527.  
  528.  
  529.  
  530. /* RWUpdate should be called in response to an update event.
  531.     it calls BeginUpdate and EndUpdate redrawing the window's
  532.     contents as necessary. */
  533. void RWUpdate(WindowPtr rWin) {
  534.     RWindowHandle rwv;
  535.     Rect r;
  536.     short i;
  537.         /* set up locals */
  538.     rwv = (RWindowHandle) GetWRefCon(rWin);
  539.     
  540.         /* set up the drawing environment */
  541.     SetPort(rWin);
  542.     SetOrigin(0, 0);
  543.     ClipRect(&rWin->portRect);
  544.     BeginUpdate(rWin);
  545.         
  546.         /* draw the button controls and the fill area at the top of the window. */
  547.     SetRect(&r, 32*(3+(**rwv).nExtraButtons), 0, rWin->portRect.right, 32);
  548.     DrawFillBar(&r);
  549.     RedrawWindowButtons(rwv);
  550.     for (i=0; i<(**rwv).nExtraButtons; i++)
  551.         DrawCIconButton((**rwv).extraButtons[i], kCBup);
  552.         
  553.         /* draw a one pixel border at the bottom of that area */
  554.     MoveTo(0, 32);
  555.     LineTo(rWin->portRect.right-1, 32);
  556.  
  557.         /* if the window is not active, then gray out everything we
  558.         just drew.  */
  559.     if ( ! (**rwv).isActive) {
  560.         SetRect(&r, 0, 0, rWin->portRect.right, 33);
  561.         GrayOutBox(&r);
  562.     }
  563.         
  564.         /* draw the grow icon */
  565.     DrawGrowIconWithoutScrollLines(rWin);
  566.         
  567.         /* draw the HTML image.  we do this last as the time it takes
  568.         to complete may vary depending on the HTML content in the window.
  569.         This way, the window's structure and controls look solid and they
  570.         redraw in a consistent way. */
  571.     HRDraw((**rwv).renderer, rWin->visRgn);
  572.     
  573.         /* reset the drawing enviroment */
  574.     SetOrigin(0, 0);
  575.     EndUpdate(rWin);
  576. }
  577.  
  578.  
  579.  
  580. /* RWActivate should be called in response to activate events.*/
  581. void RWActivate(WindowPtr rWin, Boolean activate) {
  582.     RWindowHandle rwv;
  583.     Rect r;
  584.         /* set up locals */
  585.     rwv = (RWindowHandle) GetWRefCon(rWin);
  586.         /* set the active flag in the window's variables */
  587.     (**rwv).isActive = activate;
  588.         /* call the rendering library to activate or
  589.         deactivate the HTML object */
  590.     if (activate)
  591.         HRActivate((**rwv).renderer);
  592.     else HRDeactivate((**rwv).renderer);
  593.         /* post an update event so the grow icon
  594.         and the controls are re-drawn to reflect
  595.         the new active/inactive state. */
  596.     SetPort(rWin);
  597.     SetOrigin(0, 0);
  598.     SetRect(&r, 0, 0, rWin->portRect.right, 33);
  599.     InvalRect(&r);
  600.         /* ...and the grow box */
  601.     SetRect(&r, 0, 0, 16, 16);
  602.     OffsetRect(&r, rWin->portRect.right-16, rWin->portRect.bottom-16);
  603.     InvalRect(&r);
  604. }
  605.  
  606.  
  607. /* RWRecalculateSize should be called whenever the size of a rendering
  608.     window changes.  This routine resizes and redraws the windows
  609.     contents appropriately. */
  610. void RWRecalculateSize(WindowPtr rWin) {
  611.     RWindowHandle rwv;
  612.     Rect r;
  613.         /* set up locals */
  614.     rwv = (RWindowHandle) GetWRefCon(rWin);
  615.         /* set up the drawing environment */
  616.     SetPort(rWin);
  617.     SetOrigin(0, 0);
  618.         /* reset the html object's rendering area */
  619.     r = rWin->portRect;
  620.     SetRect(&r, r.left, r.top+33, r.right+1, r.bottom+1);
  621.     HRSetRenderingRect((**rwv).renderer, &r);
  622. }
  623.  
  624.  
  625. /* RWResetGotoMenu should be called before calling MenuKey or MenuSelect.  It
  626.     enables the back, forward, and home menu commands depending on what
  627.     commands are available and it rebuilds the history list at the bottom
  628.     of the go to menu. */
  629. void RWResetGotoMenu(WindowPtr rWin) {
  630.     RWindowHandle rwv;
  631.     MenuHandle goMenu;
  632.         /* set up locals */
  633.     rwv = (RWindowHandle) GetWRefCon(rWin);
  634.     goMenu = GetMenuHandle(mGo);
  635.         /* enable the back command */
  636.     if (CanGoBack((**rwv).history))
  637.         EnableItem(goMenu, iBack);
  638.     else DisableItem(goMenu, iBack);
  639.         /* enable the forward command */
  640.     if (CanGoForward((**rwv).history))
  641.         EnableItem(goMenu, iForward);
  642.     else DisableItem(goMenu, iForward);
  643.         /* enable the home command */
  644.     if (CanGoHome((**rwv).history))
  645.         EnableItem(goMenu, iHome);
  646.     else DisableItem(goMenu, iHome);
  647.         /* remove any items at the bottom of the menu */
  648.     while (CountMItems(goMenu) >= iGoSep)
  649.         DeleteMenuItem(goMenu, iGoSep);
  650.         /* append this window's history to the menu */
  651.     AppendHistoryToMenu((**rwv).history, goMenu);
  652. }
  653.  
  654.  
  655. /* RWHandleGotoMenu should be called when an item is chosen from the
  656.     go to menu.  item is the number of the item that was chosen. */
  657. void RWHandleGotoMenu(WindowPtr rWin, short item) {
  658.     RWindowHandle rwv;
  659.         /* set up locals */
  660.     rwv = (RWindowHandle) GetWRefCon(rWin);
  661.         /* err, this first part is pretty obvious...*/
  662.     if (item == iBack) {
  663.         GoBackCommand(rwv);
  664.     } else if (item == iForward) {
  665.         GoForwardCommand(rwv);
  666.     } else if (item == iHome) {
  667.         GoHomeCommand(rwv);
  668.     } else if (item > iGoSep) {
  669.         char** theURL;
  670.             /* if one of the history items is chosen from the bottom of
  671.             the menu, then we retrieve that item from the window's
  672.             history and call HRGoToURL to display it. */
  673.         if (GoToMenuItem((**rwv).history, (Handle*) &theURL, item - iGoSep) == noErr) {
  674.             MoveHHi((Handle) theURL);
  675.             HLock((Handle) theURL);
  676.             HRGoToURL((**rwv).renderer, *theURL, false, true);
  677.             SetPort(rWin);
  678.             RedrawWindowButtons(rwv);
  679.             DisposeHandle((Handle) theURL);
  680.         }
  681.     }
  682. }
  683.  
  684.  
  685. /* RWHandleMouseDown should be called in response to mouse down
  686.     events occuring inside of a rendering window.  This routine responds
  687.     to mouse clicks in the controls at the top of the window. */
  688. void RWHandleMouseDown(WindowPtr rWin, Point where) {
  689.     RWindowHandle rwv;
  690.         /* set up locals */
  691.     rwv = (RWindowHandle) GetWRefCon(rWin);
  692.     SetPort(rWin);
  693.     SetOrigin(0, 0);
  694.     ClipRect(&rWin->portRect);
  695.  
  696.         /* handle clicks in the standard buttons */
  697.     if (TrackCIconButton((**rwv).bback, where)) {
  698.         
  699.         GoBackCommand(rwv);
  700.         
  701.     } else if (TrackCIconButton((**rwv).bhome, where)) {
  702.     
  703.         GoHomeCommand(rwv);
  704.         
  705.     } else if (TrackCIconButton((**rwv).bforward, where)) {
  706.     
  707.         GoForwardCommand(rwv);
  708.         
  709.     } else {
  710.             /* if a user clicks in a custom button, then we
  711.             go to the link specified in it's data */
  712.         short i;
  713.         for (i=0; i<(**rwv).nExtraButtons; i++) {
  714.             if (TrackCIconButton((**rwv).extraButtons[i], where)) {
  715.                 OSStatus err;
  716.                 err = RWGoToButtonPage(rWin, (**rwv).extraButtons[i]);
  717.                 /* report errors here */
  718.                 DrawCIconButton((**rwv).extraButtons[i], kCBup);
  719.                 break;
  720.             }
  721.             
  722.         }
  723.     }
  724. }
  725.  
  726.  
  727. /* RWKeyDown should be called for keydown events when a rendering
  728.     window is the frontmost window.  This routine maps the left, up,
  729.     and right arrow keys to the back, home, and forward commands. */
  730. void RWKeyDown(WindowPtr rWin, char theKey) {
  731.     RWindowHandle rwv;
  732.     rwv = (RWindowHandle) GetWRefCon(rWin);
  733.     SetPort(rWin);
  734.     SetOrigin(0, 0);
  735.     ClipRect(&rWin->portRect);
  736.     switch (theKey) {
  737.         case kLeftArrowKey: /* left arrow key */
  738.             if (CanGoBack((**rwv).history)) {
  739.                 DrawCIconButton((**rwv).bback, kCBdown);
  740.                 GoBackCommand(rwv);
  741.             }
  742.             break;
  743.         case kUpArrowKey: /* up arrow key */
  744.             if (CanGoHome((**rwv).history)) {
  745.                 DrawCIconButton((**rwv).bhome, kCBdown);
  746.                 GoHomeCommand(rwv);
  747.             }
  748.             break;
  749.         case kDownArrowKey: /* right arrow key */
  750.             if (CanGoForward((**rwv).history)) {
  751.                 DrawCIconButton((**rwv).bforward, kCBdown);
  752.                 GoForwardCommand(rwv);
  753.             }
  754.             break;
  755.     }
  756. }
  757.  
  758.  
  759. /* RWOpen opens a new, empty rendering window.  If successful,
  760.     then *rWindow will contain a pointer to a newly created window. */
  761. OSStatus RWOpen(WindowPtr *rWindow) {
  762.     OSStatus err;
  763.     WindowPtr rwin;
  764.     short i, nExtraButtons;
  765.     HRReference rend; /* the window's rendering object */
  766.     HistoryDataHandle hist; /* the window's history */
  767.     RWindowHandle rwv; /* storage for the window's state variables */
  768.     RBCLRsrcHandle extraButtonIDs; /* extra button id list */
  769.     CIconButtonHandle backButton, homeButton, forwardButton;
  770.     CIconButtonHandle extraButtons[kExtraButtonsMax];
  771.         /* static globals */
  772.     static HRNewURLUPP gNewURLUPP = NULL;
  773.     static HRWasURLVisitedUPP gVisitedURLUPP = NULL;
  774.     static HRURLToFSSpecUPP gTranslateURLUPP = NULL;
  775.     static Point gPosition = { 0, 0};
  776.  
  777.         /* set up locals */
  778.     rwin = NULL;
  779.     rend = NULL;
  780.     hist = NULL;
  781.     rwv = NULL;
  782.     backButton = homeButton = forwardButton = NULL;
  783.     for (i=0; i<kExtraButtonsMax; i++) extraButtons[i] = NULL;
  784.     nExtraButtons = 0;
  785.     
  786.         /* get the buttons */
  787.     backButton = NewCIconButton(kBackDefaultButton);
  788.     if (backButton == NULL) { err = resNotFound; goto bail; }
  789.     homeButton = NewCIconButton(kHomeDefaultButton);
  790.     if (homeButton == NULL) { err = resNotFound; goto bail; }
  791.     forwardButton = NewCIconButton(kForwardDefaultButton);
  792.     if (forwardButton == NULL) { err = resNotFound; goto bail; }
  793.         /* get the extra buttons */
  794.     extraButtonIDs = (RBCLRsrcHandle) GetResource(kIconButtonIDListType, kExtraButtonsListID);
  795.     if (extraButtonIDs != NULL) {
  796.         nExtraButtons = (**extraButtonIDs).n;
  797.         if (nExtraButtons > kExtraButtonsMax) nExtraButtons = kExtraButtonsMax;
  798.         for (i=0; i < nExtraButtons; i++) {
  799.             extraButtons[i] = NewCIconButton((**extraButtonIDs).ids[i]);
  800.             if (extraButtons[i] == NULL) { err = resNotFound; goto bail; }
  801.             SetCIconButtonPosition(extraButtons[i], 32 * (3 + i), 0);
  802.         }
  803.     }
  804.  
  805.         /* allocate the window */
  806.     rwin = GetNewCWindow(kRenderingWindowID, NULL, (WindowPtr)(-1));
  807.     if (rwin == NULL) { err = resNotFound; goto bail; }
  808.     SetPort(rwin);
  809.         /* position it on the screen */
  810.     MoveWindow(rwin, gPosition.h + 20, gPosition.v + 50, true);
  811.     gPosition.h = (gPosition.h + 10) % 300;
  812.     gPosition.v = (gPosition.v + 32) % 200;
  813.         /* set up the renderer */
  814.     err = HRNewReference(&rend, kHRRendererHTML32Type, rwin);
  815.     if (err != noErr) goto bail;
  816.     err = HRSetGrowboxCutout(rend, true);
  817.     if (err != noErr) goto bail;
  818.         /* create the history */
  819.     hist = NewHistory();
  820.     if (hist == NULL) { err = memFullErr; goto bail; }
  821.         /* allocate the storage and store a handle to it in the refcon */
  822.     rwv = (RWindowHandle) NewHandleClear(offsetof(RWindowVars, extraButtons) + sizeof(CIconButtonHandle)*nExtraButtons);
  823.     if (rwv == NULL) { err = memFullErr; goto bail; }
  824.     (**rwv).rwindow = rwin;
  825.     (**rwv).renderer = rend;
  826.     (**rwv).history = hist;
  827.     (**rwv).isActive = false;
  828.     (**rwv).bback = backButton;
  829.     (**rwv).bhome = homeButton;
  830.     (**rwv).bforward = forwardButton;
  831.     (**rwv).nExtraButtons = nExtraButtons;
  832.     for (i=0; i<nExtraButtons; i++)
  833.         (**rwv).extraButtons[i] = extraButtons[i];
  834.     SetWRefCon(rwin, (long) rwv);
  835.         /* set up the new links call back */
  836.     if (gNewURLUPP == NULL) {
  837.         gNewURLUPP = NewHRNewURLUPP(MyNewURLProc);
  838.         if (gNewURLUPP == NULL) { err = memFullErr; goto bail; }
  839.     }
  840.     HRRegisterNewURLUPP( gNewURLUPP, rend, rwv);
  841.         /* set up the visited links call back */
  842.     if (gVisitedURLUPP == NULL) {
  843.         gVisitedURLUPP = NewHRWasURLVisitedUPP(MyHRWasURLVisitedProc);
  844.         if (gVisitedURLUPP == NULL) { err = memFullErr; goto bail; }
  845.     }
  846.     HRRegisterWasURLVisitedUPP( gVisitedURLUPP, rend, rwv);
  847.         /* set up the link translation call back */
  848.     if (gTranslateURLUPP == NULL) {
  849.         gTranslateURLUPP = NewHRURLToFSSpecUPP(MyHRURLToFSSpecProc);
  850.         if (gTranslateURLUPP == NULL) { err = memFullErr; goto bail; }
  851.     }
  852.     HRRegisterURLToFSSpecUPP( gTranslateURLUPP, rend, rwv);
  853.         /* add the window to the list of open windows */
  854.     if (gRWFirst == NULL) {
  855.         gRWFirst = gRWLast = rwv;
  856.     } else {
  857.         (**rwv).next = gRWFirst;
  858.         (**gRWFirst).prev = rwv;
  859.         gRWFirst = rwv;
  860.     }
  861.         /* recalculate the window's coordinates and show it */
  862.     RWRecalculateSize(rwin);
  863.     ShowWindow(rwin);
  864.     *rWindow = rwin;
  865.     return noErr;
  866.  
  867. bail:
  868.         /* if an error occurs, we recover and return the error code */
  869.     if (hist != NULL) DisposeHistory(hist);
  870.     if (rend != NULL) HRDisposeReference(rend);
  871.     if (rwin != NULL) DisposeWindow(rwin);
  872.     if (rwv != NULL) DisposeHandle((Handle) rwv);
  873.     if (backButton != NULL) DisposeCIconButton(backButton);
  874.     if (homeButton != NULL) DisposeCIconButton(homeButton);
  875.     if (forwardButton != NULL) DisposeCIconButton(forwardButton);
  876.     for (i=0; i < nExtraButtons; i++) {
  877.         if (extraButtons[i] != NULL) DisposeCIconButton(extraButtons[i]);
  878.     }
  879.     return err;
  880. }
  881.  
  882.  
  883. /* RWCloseWindow closes the rendering window pointed to by
  884.     rWin.  */
  885. void RWCloseWindow(WindowPtr rWin) {
  886.     RWindowHandle rwv;
  887.     short i;
  888.         /* set up locals */
  889.     rwv = (RWindowHandle) GetWRefCon(rWin);
  890.         /* delete the rendering object */
  891.     HRDisposeReference((**rwv).renderer);
  892.         /* delete the history */
  893.     DisposeHistory((**rwv).history);
  894.         /* deallocate the window */
  895.     DisposeWindow((**rwv).rwindow);
  896.         /* delete the icons */
  897.     DisposeCIconButton((**rwv).bback);
  898.     DisposeCIconButton((**rwv).bhome);
  899.     DisposeCIconButton((**rwv).bforward);
  900.     for (i=0; i < (**rwv).nExtraButtons; i++)
  901.         DisposeCIconButton((**rwv).extraButtons[i]);
  902.         /* remove from the rendering window list */
  903.     if ((**rwv).next != NULL)
  904.         (**(**rwv).next).prev = (**rwv).prev;
  905.     else gRWLast = (*rwv)->prev;
  906.     if ((**rwv).prev != NULL)
  907.         (**(**rwv).prev).next = (**rwv).next;
  908.     else gRWFirst = (**rwv).next;
  909.         /* delete storage */
  910.     DisposeHandle((Handle) rwv);
  911. }
  912.  
  913.  
  914. /* IsARenderingWindow returns true if rWin points to a rendering
  915.     window created by RWOpen. You should not call any of the routines
  916.     below for windows that are not rendering windows.  This routine
  917.     provides a convenient way to tell if a windowptr returned by one
  918.     of the toolbox routines is a rendering window. */
  919. Boolean IsARenderingWindow(WindowPtr rWin) {
  920.     RWindowHandle rover;
  921.         /* a null pointer cannot refer to a rendering window */
  922.     if (rWin == NULL) return false;
  923.         /* search the list of windows and see if it's there */
  924.     for (rover = gRWFirst; rover != NULL; rover = (**rover).next)
  925.         if (rWin == (**rover).rwindow)
  926.             return true;
  927.         /* if it's not there, return false. */    
  928.     return false;
  929. }
  930.